package com.boe.server.register.config;

import com.boe.server.register.security.filter.JWTAuthenticationTokenFilter;
import com.boe.server.register.security.handler.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final UserDetailsService userDetailsService;

    private final UserAuthAccessDeniedHandler userAuthAccessDeniedHandler;

    private final UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler;

    private final UserLoginSuccessHandler userLoginSuccessHandler;

    private final UserLoginFailureHandler userLoginFailureHandler;

    private final UserLogoutSuccessHandler userLogoutSuccessHandler;

    private final JWTConfig jwtConfig;


    public SecurityConfig(@Qualifier("userDetailsServiceImpl") UserDetailsService userDetailsService,
                          UserAuthAccessDeniedHandler userAuthAccessDeniedHandler,
                          UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler,
                          UserLoginSuccessHandler userLoginSuccessHandler,
                          UserLoginFailureHandler userLoginFailureHandler,
                          UserLogoutSuccessHandler userLogoutSuccessHandler,
                          JWTConfig jwtConfig) {
        this.userDetailsService = userDetailsService;
        this.userAuthAccessDeniedHandler = userAuthAccessDeniedHandler;
        this.userAuthenticationEntryPointHandler = userAuthenticationEntryPointHandler;
        this.userLoginSuccessHandler = userLoginSuccessHandler;
        this.userLoginFailureHandler = userLoginFailureHandler;
        this.userLogoutSuccessHandler = userLogoutSuccessHandler;
        this.jwtConfig = jwtConfig;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(encoder());
    }

    @Bean
    PasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers(jwtConfig.getPermitAll()).permitAll()
                .anyRequest().authenticated()
                .and()
                .httpBasic().authenticationEntryPoint(userAuthenticationEntryPointHandler)
                .and()
                .formLogin()
                .loginProcessingUrl("/login")
                .successHandler(userLoginSuccessHandler)
                .failureHandler(userLoginFailureHandler)
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler(userLogoutSuccessHandler)
                .and()
                .exceptionHandling().accessDeniedHandler(userAuthAccessDeniedHandler)
                .and()
                .cors()
                .and()
                .csrf().disable();

        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.headers().cacheControl();
        http.addFilter(jwtAuthenticationTokenFilter());
    }

    @Bean
    JWTAuthenticationTokenFilter jwtAuthenticationTokenFilter() throws Exception {
        return new JWTAuthenticationTokenFilter(authenticationManager(), jwtConfig);
    }

}
